package org.argus.common.mybatis.handler;

import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.argus.common.core.exception.ServiceException;
import org.argus.common.core.token.ITokenManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * @Author 刘文/Cliff Liu
 * @Date 2024/8/21
 */
@Component
@Slf4j
public class DomainTenantHandler implements TenantLineHandler {

    @Autowired
    private TenantProperties properties;

    @Autowired
    private ITokenManager tokenManager;

    private Set<String> ignoreTableNames = new HashSet<>();

    private List<String> ignoreTablePrefixes = new LinkedList<>();

    @PostConstruct
    public void init() {
        if (properties.getIgnoreTables() != null) {
            ignoreTableNames.addAll(properties.getIgnoreTables());
        }
        if (properties.getIgnoreTablePrefixes() != null) {
            ignoreTablePrefixes.addAll(properties.getIgnoreTablePrefixes());
        }
    }

    /**
     * 获取租户ID值表达式，只支持单个ID值 (实际应该从用户信息中获取)
     *
     * @return 租户ID值表达式
     */
    @Override
    public Expression getTenantId() {
        // 实际应该从用户信息中获取
        Long userCurrentDomainId = tokenManager.getUserCurrentDomainId();
        if (userCurrentDomainId != null) {
            return new LongValue(userCurrentDomainId);
        }

        log.warn("Get current user domain id faild");
        return new LongValue(-1l);
    }

    /**
     * 获取租户字段名,默认字段名叫: tenant_id
     *
     * @return 租户字段名
     */
    @Override
    public String getTenantIdColumn() {
        return properties.getColumn();
    }

    /**
     * 根据表名判断是否忽略拼接多租户条件
     *
     * 默认都要进行解析并拼接多租户条件
     *
     * @param tableName 表名
     * @return 是否忽略, true:表示忽略，false:需要解析并拼接多租户条件
     */
    @Override
    public boolean ignoreTable(String tableName) {
        // 无法获取用于域信息，不做域隔离处理
        if (tokenManager.getUserCurrentDomainId() == null) {
            return true;
        }

        // 忽略指定表对租户数据的过滤
        if (ignoreTableNames.contains(tableName)) {
            return true;
        }

        return ignoreTablePrefixes.stream().anyMatch(tableName::startsWith);
    }
}
